@dogsbay/format-dogsbay-md 0.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attributes.d.ts +33 -0
- package/dist/attributes.d.ts.map +1 -0
- package/dist/attributes.js +83 -0
- package/dist/attributes.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +129 -0
- package/dist/cli.js.map +1 -0
- package/dist/directives.d.ts +19 -0
- package/dist/directives.d.ts.map +1 -0
- package/dist/directives.js +76 -0
- package/dist/directives.js.map +1 -0
- package/dist/escape.d.ts +42 -0
- package/dist/escape.d.ts.map +1 -0
- package/dist/escape.js +79 -0
- package/dist/escape.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/inline.d.ts +9 -0
- package/dist/inline.d.ts.map +1 -0
- package/dist/inline.js +122 -0
- package/dist/inline.js.map +1 -0
- package/dist/nav-file.d.ts +38 -0
- package/dist/nav-file.d.ts.map +1 -0
- package/dist/nav-file.js +257 -0
- package/dist/nav-file.js.map +1 -0
- package/dist/nav.d.ts +34 -0
- package/dist/nav.d.ts.map +1 -0
- package/dist/nav.js +169 -0
- package/dist/nav.js.map +1 -0
- package/dist/parse-attrs.d.ts +24 -0
- package/dist/parse-attrs.d.ts.map +1 -0
- package/dist/parse-attrs.js +117 -0
- package/dist/parse-attrs.js.map +1 -0
- package/dist/parse.d.ts +18 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +1076 -0
- package/dist/parse.js.map +1 -0
- package/dist/plugin-block-leaf.d.ts +19 -0
- package/dist/plugin-block-leaf.d.ts.map +1 -0
- package/dist/plugin-block-leaf.js +81 -0
- package/dist/plugin-block-leaf.js.map +1 -0
- package/dist/plugin-containers.d.ts +11 -0
- package/dist/plugin-containers.d.ts.map +1 -0
- package/dist/plugin-containers.js +63 -0
- package/dist/plugin-containers.js.map +1 -0
- package/dist/plugin-inline-directives.d.ts +18 -0
- package/dist/plugin-inline-directives.d.ts.map +1 -0
- package/dist/plugin-inline-directives.js +121 -0
- package/dist/plugin-inline-directives.js.map +1 -0
- package/dist/serialize.d.ts +25 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +712 -0
- package/dist/serialize.js.map +1 -0
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/yaml.d.ts +22 -0
- package/dist/yaml.d.ts.map +1 -0
- package/dist/yaml.js +113 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribute rendering — produces `{ #id .class1 .class2 key="value" }` blocks
|
|
3
|
+
* following the markdown-it-attrs syntax.
|
|
4
|
+
*
|
|
5
|
+
* Ordering convention: id first, then classes, then key=value attributes.
|
|
6
|
+
* Empty attrs return "".
|
|
7
|
+
*/
|
|
8
|
+
export interface RenderedAttrs {
|
|
9
|
+
id?: string;
|
|
10
|
+
classes?: string[];
|
|
11
|
+
props?: Record<string, string | number | boolean | undefined>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Render an attribute block.
|
|
15
|
+
* Returns `{ #id .a .b key="value" }` or "" if no attrs.
|
|
16
|
+
* Leading space included so callers can append directly to content.
|
|
17
|
+
*/
|
|
18
|
+
export declare function renderAttrs(attrs: RenderedAttrs): string;
|
|
19
|
+
/**
|
|
20
|
+
* Escape an attribute value for inclusion in {key="value"}.
|
|
21
|
+
* Always double-quotes; escapes embedded quotes and backslashes.
|
|
22
|
+
* Normalizes newlines to spaces since attribute values must be single-line
|
|
23
|
+
* (multi-line values should use YAML body form, not {attrs}).
|
|
24
|
+
*/
|
|
25
|
+
export declare function escapeAttrValue(value: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Split a free-form props record into RenderedAttrs, extracting `id` and `class`/`className`
|
|
28
|
+
* into their structured form. Unknown keys stay in `props`.
|
|
29
|
+
*
|
|
30
|
+
* This is the common glue between TreeNode.props and attribute output.
|
|
31
|
+
*/
|
|
32
|
+
export declare function splitProps(props: Record<string, unknown> | undefined, excludeKeys?: string[]): RenderedAttrs;
|
|
33
|
+
//# sourceMappingURL=attributes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;CAC/D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CA0BxD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC1C,WAAW,GAAE,MAAM,EAAO,GACzB,aAAa,CA8Bf"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribute rendering — produces `{ #id .class1 .class2 key="value" }` blocks
|
|
3
|
+
* following the markdown-it-attrs syntax.
|
|
4
|
+
*
|
|
5
|
+
* Ordering convention: id first, then classes, then key=value attributes.
|
|
6
|
+
* Empty attrs return "".
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Render an attribute block.
|
|
10
|
+
* Returns `{ #id .a .b key="value" }` or "" if no attrs.
|
|
11
|
+
* Leading space included so callers can append directly to content.
|
|
12
|
+
*/
|
|
13
|
+
export function renderAttrs(attrs) {
|
|
14
|
+
const parts = [];
|
|
15
|
+
if (attrs.id) {
|
|
16
|
+
parts.push(`#${attrs.id}`);
|
|
17
|
+
}
|
|
18
|
+
if (attrs.classes) {
|
|
19
|
+
for (const cls of attrs.classes) {
|
|
20
|
+
if (cls)
|
|
21
|
+
parts.push(`.${cls}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (attrs.props) {
|
|
25
|
+
for (const [key, value] of Object.entries(attrs.props)) {
|
|
26
|
+
if (value === undefined || value === null || value === false)
|
|
27
|
+
continue;
|
|
28
|
+
if (value === true) {
|
|
29
|
+
parts.push(key);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
parts.push(`${key}=${escapeAttrValue(String(value))}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (parts.length === 0)
|
|
36
|
+
return "";
|
|
37
|
+
return `{${parts.join(" ")}}`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Escape an attribute value for inclusion in {key="value"}.
|
|
41
|
+
* Always double-quotes; escapes embedded quotes and backslashes.
|
|
42
|
+
* Normalizes newlines to spaces since attribute values must be single-line
|
|
43
|
+
* (multi-line values should use YAML body form, not {attrs}).
|
|
44
|
+
*/
|
|
45
|
+
export function escapeAttrValue(value) {
|
|
46
|
+
const normalized = value.replace(/\r?\n/g, " ").replace(/\s+/g, " ");
|
|
47
|
+
return `"${normalized.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Split a free-form props record into RenderedAttrs, extracting `id` and `class`/`className`
|
|
51
|
+
* into their structured form. Unknown keys stay in `props`.
|
|
52
|
+
*
|
|
53
|
+
* This is the common glue between TreeNode.props and attribute output.
|
|
54
|
+
*/
|
|
55
|
+
export function splitProps(props, excludeKeys = []) {
|
|
56
|
+
const result = {};
|
|
57
|
+
if (!props)
|
|
58
|
+
return result;
|
|
59
|
+
const exclude = new Set(excludeKeys);
|
|
60
|
+
const cleanProps = {};
|
|
61
|
+
for (const [key, value] of Object.entries(props)) {
|
|
62
|
+
if (exclude.has(key))
|
|
63
|
+
continue;
|
|
64
|
+
if (key === "id" && typeof value === "string") {
|
|
65
|
+
result.id = value;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if ((key === "class" || key === "className") && typeof value === "string") {
|
|
69
|
+
result.classes = value.split(/\s+/).filter(Boolean);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (value === null || value === undefined)
|
|
73
|
+
continue;
|
|
74
|
+
if (typeof value === "object")
|
|
75
|
+
continue; // skip nested structures
|
|
76
|
+
cleanProps[key] = value;
|
|
77
|
+
}
|
|
78
|
+
if (Object.keys(cleanProps).length > 0) {
|
|
79
|
+
result.props = cleanProps;
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=attributes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAgC,MAAM,gBAAgB,CAAC;AA2HjF,eAAO,MAAM,MAAM,EAAE,YAcpB,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FormatPlugin for Dogsbay MD as a source format.
|
|
3
|
+
*
|
|
4
|
+
* Reads a directory of .md files, parses each via dogsbayMdToTree, builds nav
|
|
5
|
+
* from directory structure + frontmatter, returns ExportPage[] + NavItem[].
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
8
|
+
import { join, relative, basename } from "node:path";
|
|
9
|
+
import { parseMeta } from "@dogsbay/types";
|
|
10
|
+
import { dogsbayMdToTree } from "./parse.js";
|
|
11
|
+
import { buildNavFromDirectory } from "./nav.js";
|
|
12
|
+
/**
|
|
13
|
+
* Detect whether a directory contains a Dogsbay MD source tree.
|
|
14
|
+
*
|
|
15
|
+
* Heuristic: at least one .md file with frontmatter in the directory or
|
|
16
|
+
* any immediate subdirectory. We don't fail if the heuristic misses — the
|
|
17
|
+
* CLI allows explicit --from dogsbay-md.
|
|
18
|
+
*/
|
|
19
|
+
function detectDogsbayMdSource(path) {
|
|
20
|
+
if (!existsSync(path))
|
|
21
|
+
return false;
|
|
22
|
+
try {
|
|
23
|
+
const st = statSync(path);
|
|
24
|
+
if (!st.isDirectory())
|
|
25
|
+
return false;
|
|
26
|
+
const entries = readdirSync(path, { recursive: true });
|
|
27
|
+
return entries.some((e) => e.endsWith(".md"));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function walkMdFiles(dir, root, out = []) {
|
|
34
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
35
|
+
const full = join(dir, entry.name);
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
walkMdFiles(full, root, out);
|
|
38
|
+
}
|
|
39
|
+
else if (entry.name.endsWith(".md")) {
|
|
40
|
+
const rel = relative(root, full).replace(/\\/g, "/");
|
|
41
|
+
const slug = rel.replace(/\.md$/, "");
|
|
42
|
+
out.push({ filePath: full, slug });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
async function importDogsbayMd(source, opts) {
|
|
48
|
+
if (!existsSync(source)) {
|
|
49
|
+
throw new Error(`Source directory not found: ${source}`);
|
|
50
|
+
}
|
|
51
|
+
const st = statSync(source);
|
|
52
|
+
if (!st.isDirectory()) {
|
|
53
|
+
throw new Error(`Source must be a directory: ${source}`);
|
|
54
|
+
}
|
|
55
|
+
const files = walkMdFiles(source, source);
|
|
56
|
+
const pages = [];
|
|
57
|
+
// Taxonomy names declared in dogsbay.config.yml's `taxonomies:` block;
|
|
58
|
+
// wired through cli's import-content.ts. parseMeta uses these to lift
|
|
59
|
+
// user-declared taxonomy keys (e.g. `audience`, `product`) into
|
|
60
|
+
// meta.taxonomies. Absent for standalone CLI invocations.
|
|
61
|
+
const taxonomyNames = Array.isArray(opts.taxonomyNames)
|
|
62
|
+
? opts.taxonomyNames
|
|
63
|
+
: undefined;
|
|
64
|
+
for (const { filePath, slug } of files) {
|
|
65
|
+
const content = readFileSync(filePath, "utf-8");
|
|
66
|
+
const { tree, frontmatter } = dogsbayMdToTree(content);
|
|
67
|
+
const title = String(frontmatter.title
|
|
68
|
+
?? prettifyName(basename(slug)));
|
|
69
|
+
// Extract heading metadata for TOC
|
|
70
|
+
const headings = [];
|
|
71
|
+
for (const node of tree) {
|
|
72
|
+
if (node.type === "heading" && node.inline) {
|
|
73
|
+
const text = node.inline
|
|
74
|
+
.map((n) => (n.type === "text" ? n.text : ""))
|
|
75
|
+
.join("")
|
|
76
|
+
.trim();
|
|
77
|
+
headings.push({
|
|
78
|
+
depth: node.props?.level ?? 1,
|
|
79
|
+
slug: node.props?.slug ?? slugify(text),
|
|
80
|
+
text,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const redirect = frontmatter.redirect;
|
|
85
|
+
const meta = parseMeta(frontmatter, { slug, taxonomyNames });
|
|
86
|
+
pages.push({
|
|
87
|
+
slug,
|
|
88
|
+
title,
|
|
89
|
+
tree,
|
|
90
|
+
headings,
|
|
91
|
+
redirect,
|
|
92
|
+
frontmatter,
|
|
93
|
+
meta,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const navFilePath = opts.nav || undefined;
|
|
97
|
+
const hrefPrefix = typeof opts.hrefPrefix === "string" ? opts.hrefPrefix : undefined;
|
|
98
|
+
const nav = buildNavFromDirectory(source, { navFilePath, hrefPrefix });
|
|
99
|
+
return { pages, nav };
|
|
100
|
+
}
|
|
101
|
+
function prettifyName(slug) {
|
|
102
|
+
return slug
|
|
103
|
+
.split(/[-_]/)
|
|
104
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
105
|
+
.join(" ");
|
|
106
|
+
}
|
|
107
|
+
function slugify(text) {
|
|
108
|
+
return text
|
|
109
|
+
.toLowerCase()
|
|
110
|
+
.replace(/[^\w\s-]/g, "")
|
|
111
|
+
.trim()
|
|
112
|
+
.replace(/\s+/g, "-");
|
|
113
|
+
}
|
|
114
|
+
export const plugin = {
|
|
115
|
+
name: "dogsbay-md",
|
|
116
|
+
canImport: true,
|
|
117
|
+
canExport: false,
|
|
118
|
+
detectSource: detectDogsbayMdSource,
|
|
119
|
+
importOptions: [
|
|
120
|
+
{
|
|
121
|
+
flags: "--nav <path>",
|
|
122
|
+
description: "Path to an explicit nav file (.json/.yml/.yaml). Overrides heuristic auto-detection of nav.json / nav.yml / nav.yaml in the content root.",
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
async import(source, opts) {
|
|
126
|
+
return importDogsbayMd(source, opts);
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ResolvedOptions } from "./types.js";
|
|
2
|
+
export interface DirectiveRenderInput {
|
|
3
|
+
/** Directive name, e.g. "card", "tabs", "steps" */
|
|
4
|
+
name: string;
|
|
5
|
+
/** Props to emit as attrs or YAML body */
|
|
6
|
+
props?: Record<string, unknown>;
|
|
7
|
+
/** Keys to exclude from props (already rendered elsewhere) */
|
|
8
|
+
excludeProps?: string[];
|
|
9
|
+
/** Body content (already serialized markdown) */
|
|
10
|
+
body?: string;
|
|
11
|
+
/** Opts into YAML body form for prop-heavy cases */
|
|
12
|
+
yamlEligible?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Render a block directive. Chooses attrs-form vs yaml-body form based on
|
|
16
|
+
* the component, option threshold, and prop complexity.
|
|
17
|
+
*/
|
|
18
|
+
export declare function renderBlockDirective(input: DirectiveRenderInput, ctx: ResolvedOptions): string;
|
|
19
|
+
//# sourceMappingURL=directives.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../src/directives.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,oBAAoB,EAC3B,GAAG,EAAE,eAAe,GACnB,MAAM,CAwBR"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Directive rendering for block components (card, tabs, steps, cards, api-endpoint, ...).
|
|
3
|
+
*
|
|
4
|
+
* Two attribute forms:
|
|
5
|
+
* - Inline: `:::name{key="value" .class}` — compact, for simple prop sets
|
|
6
|
+
* - YAML: `:::name\n---\nkey: value\n---\nbody` — for prop-heavy components
|
|
7
|
+
*
|
|
8
|
+
* Heuristic: use YAML when the prop count exceeds threshold OR any string value
|
|
9
|
+
* contains a newline OR a nested object/array is present. Only components on
|
|
10
|
+
* the YAML opt-in list use the YAML form; others always use inline attrs.
|
|
11
|
+
*/
|
|
12
|
+
import { renderAttrs, splitProps } from "./attributes.js";
|
|
13
|
+
import { pickDirectiveFence } from "./escape.js";
|
|
14
|
+
import { renderYaml } from "./yaml.js";
|
|
15
|
+
/**
|
|
16
|
+
* Render a block directive. Chooses attrs-form vs yaml-body form based on
|
|
17
|
+
* the component, option threshold, and prop complexity.
|
|
18
|
+
*/
|
|
19
|
+
export function renderBlockDirective(input, ctx) {
|
|
20
|
+
const { name, props, excludeProps = [], body = "" } = input;
|
|
21
|
+
const yamlEligible = input.yamlEligible ?? ctx.yamlComponents.has(name);
|
|
22
|
+
const attrs = splitProps(props, excludeProps);
|
|
23
|
+
const useYaml = yamlEligible && shouldUseYaml(attrs, ctx);
|
|
24
|
+
const fence = pickDirectiveFence(useYaml ? body + "\n---" : body);
|
|
25
|
+
if (!useYaml) {
|
|
26
|
+
const attrStr = renderAttrs(attrs);
|
|
27
|
+
const opener = attrStr ? `${fence}${name}${attrStr}` : `${fence}${name}`;
|
|
28
|
+
return `${opener}\n${body}\n${fence}`;
|
|
29
|
+
}
|
|
30
|
+
// YAML body form — emit all props (including id, classes) as yaml keys
|
|
31
|
+
const yamlData = attrsToYaml(attrs);
|
|
32
|
+
const yaml = renderYaml(yamlData);
|
|
33
|
+
const header = yaml.length > 0 ? `---\n${yaml}\n---` : "";
|
|
34
|
+
if (!body) {
|
|
35
|
+
return `${fence}${name}\n${header}\n${fence}`;
|
|
36
|
+
}
|
|
37
|
+
return `${fence}${name}\n${header}\n${body}\n${fence}`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Decide if a set of attributes warrants YAML body form.
|
|
41
|
+
*/
|
|
42
|
+
function shouldUseYaml(attrs, ctx) {
|
|
43
|
+
const propCount = (attrs.id ? 1 : 0) +
|
|
44
|
+
(attrs.classes?.length ?? 0) +
|
|
45
|
+
Object.keys(attrs.props ?? {}).length;
|
|
46
|
+
if (propCount > ctx.yamlThreshold)
|
|
47
|
+
return true;
|
|
48
|
+
// Multi-line or complex string values force YAML
|
|
49
|
+
if (attrs.props) {
|
|
50
|
+
for (const value of Object.values(attrs.props)) {
|
|
51
|
+
if (typeof value === "string" && value.includes("\n"))
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert RenderedAttrs back into a yaml-shaped object.
|
|
59
|
+
*/
|
|
60
|
+
function attrsToYaml(attrs) {
|
|
61
|
+
const result = {};
|
|
62
|
+
if (attrs.id)
|
|
63
|
+
result.id = attrs.id;
|
|
64
|
+
if (attrs.classes && attrs.classes.length > 0) {
|
|
65
|
+
result.class = attrs.classes.join(" ");
|
|
66
|
+
}
|
|
67
|
+
if (attrs.props) {
|
|
68
|
+
for (const [key, value] of Object.entries(attrs.props)) {
|
|
69
|
+
if (value === undefined)
|
|
70
|
+
continue;
|
|
71
|
+
result[key] = value;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=directives.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directives.js","sourceRoot":"","sources":["../src/directives.ts"],"names":[],"mappings":"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"}
|
package/dist/escape.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escape helpers for Dogsbay Markdown output.
|
|
3
|
+
*
|
|
4
|
+
* Two rules drive everything here:
|
|
5
|
+
* 1. Content must round-trip through a markdown-it parser cleanly.
|
|
6
|
+
* 2. When ambiguous, prefer escaping — a reader never sees broken syntax.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Escape markdown-active characters in text content.
|
|
10
|
+
* Only escapes what would change parsing; leaves everything else alone.
|
|
11
|
+
*/
|
|
12
|
+
export declare function escapeText(text: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Escape text that appears inside an attribute `{...}` block.
|
|
15
|
+
* Double-quotes already handled by escapeAttrValue; this is for bareword values.
|
|
16
|
+
*/
|
|
17
|
+
export declare function escapeAttrBareword(text: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Pick a code fence delimiter that doesn't collide with the content.
|
|
20
|
+
* Returns the shortest fence longer than any backtick/tilde run in the content.
|
|
21
|
+
*
|
|
22
|
+
* @param content - code to be fenced
|
|
23
|
+
* @param preferredChar - backtick or tilde; defaults to backtick
|
|
24
|
+
* @returns fence string (e.g. "```", "````", "~~~~~")
|
|
25
|
+
*/
|
|
26
|
+
export declare function pickCodeFence(content: string, preferredChar?: "`" | "~"): string;
|
|
27
|
+
/**
|
|
28
|
+
* Pick a container directive fence of colons that doesn't collide with content.
|
|
29
|
+
* Minimum is 3 colons (`:::`); scales up when content contains longer runs.
|
|
30
|
+
*/
|
|
31
|
+
export declare function pickDirectiveFence(content: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Indent every non-empty line of `content` by `spaces`.
|
|
34
|
+
* Preserves blank lines untouched.
|
|
35
|
+
*/
|
|
36
|
+
export declare function indent(content: string, spaces: number): string;
|
|
37
|
+
/**
|
|
38
|
+
* Normalize trailing whitespace: ensure single trailing newline, strip
|
|
39
|
+
* more than two consecutive blank lines.
|
|
40
|
+
*/
|
|
41
|
+
export declare function normalizeTrailingWhitespace(content: string): string;
|
|
42
|
+
//# sourceMappingURL=escape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../src/escape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,aAAa,GAAE,GAAG,GAAG,GAAS,GAC7B,MAAM,CAOR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKnE"}
|
package/dist/escape.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escape helpers for Dogsbay Markdown output.
|
|
3
|
+
*
|
|
4
|
+
* Two rules drive everything here:
|
|
5
|
+
* 1. Content must round-trip through a markdown-it parser cleanly.
|
|
6
|
+
* 2. When ambiguous, prefer escaping — a reader never sees broken syntax.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Escape markdown-active characters in text content.
|
|
10
|
+
* Only escapes what would change parsing; leaves everything else alone.
|
|
11
|
+
*/
|
|
12
|
+
export function escapeText(text) {
|
|
13
|
+
return text
|
|
14
|
+
.replace(/\\/g, "\\\\")
|
|
15
|
+
.replace(/([*_`~[\]()<>#|{}])/g, "\\$1");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Escape text that appears inside an attribute `{...}` block.
|
|
19
|
+
* Double-quotes already handled by escapeAttrValue; this is for bareword values.
|
|
20
|
+
*/
|
|
21
|
+
export function escapeAttrBareword(text) {
|
|
22
|
+
// Barewords must not contain whitespace, quotes, or braces.
|
|
23
|
+
if (/[\s"'{}]/.test(text)) {
|
|
24
|
+
return `"${text.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
25
|
+
}
|
|
26
|
+
return text;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Pick a code fence delimiter that doesn't collide with the content.
|
|
30
|
+
* Returns the shortest fence longer than any backtick/tilde run in the content.
|
|
31
|
+
*
|
|
32
|
+
* @param content - code to be fenced
|
|
33
|
+
* @param preferredChar - backtick or tilde; defaults to backtick
|
|
34
|
+
* @returns fence string (e.g. "```", "````", "~~~~~")
|
|
35
|
+
*/
|
|
36
|
+
export function pickCodeFence(content, preferredChar = "`") {
|
|
37
|
+
const pattern = new RegExp(`${preferredChar === "`" ? "`" : "~"}{3,}`, "g");
|
|
38
|
+
let maxRun = 2;
|
|
39
|
+
for (const match of content.matchAll(pattern)) {
|
|
40
|
+
if (match[0].length > maxRun)
|
|
41
|
+
maxRun = match[0].length;
|
|
42
|
+
}
|
|
43
|
+
return preferredChar.repeat(maxRun + 1);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Pick a container directive fence of colons that doesn't collide with content.
|
|
47
|
+
* Minimum is 3 colons (`:::`); scales up when content contains longer runs.
|
|
48
|
+
*/
|
|
49
|
+
export function pickDirectiveFence(content) {
|
|
50
|
+
const pattern = /:{3,}/g;
|
|
51
|
+
let maxRun = 2;
|
|
52
|
+
for (const match of content.matchAll(pattern)) {
|
|
53
|
+
if (match[0].length > maxRun)
|
|
54
|
+
maxRun = match[0].length;
|
|
55
|
+
}
|
|
56
|
+
return ":".repeat(maxRun + 1);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Indent every non-empty line of `content` by `spaces`.
|
|
60
|
+
* Preserves blank lines untouched.
|
|
61
|
+
*/
|
|
62
|
+
export function indent(content, spaces) {
|
|
63
|
+
const pad = " ".repeat(spaces);
|
|
64
|
+
return content
|
|
65
|
+
.split("\n")
|
|
66
|
+
.map((line) => (line.length > 0 ? pad + line : line))
|
|
67
|
+
.join("\n");
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Normalize trailing whitespace: ensure single trailing newline, strip
|
|
71
|
+
* more than two consecutive blank lines.
|
|
72
|
+
*/
|
|
73
|
+
export function normalizeTrailingWhitespace(content) {
|
|
74
|
+
return content
|
|
75
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
76
|
+
.replace(/[ \t]+$/gm, "")
|
|
77
|
+
.replace(/\s*$/, "\n");
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=escape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape.js","sourceRoot":"","sources":["../src/escape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI;SACR,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;SACtB,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,4DAA4D;IAC5D,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;IACjE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,gBAA2B,GAAG;IAE9B,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,GAAG,aAAa,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5E,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM;YAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,CAAC;IACD,OAAO,aAAa,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,OAAO,GAAG,QAAQ,CAAC;IACzB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM;YAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,OAAe,EAAE,MAAc;IACpD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,OAAO;SACX,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SACpD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAAe;IACzD,OAAO,OAAO;SACX,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;SACxB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC3B,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { treeToDogsbayMd, nodeToDogsbayMd } from "./serialize.js";
|
|
2
|
+
export type { SerializeOptions } from "./types.js";
|
|
3
|
+
export { inlineToDogsbayMd } from "./inline.js";
|
|
4
|
+
export { dogsbayMdToTree, parseInline } from "./parse.js";
|
|
5
|
+
export type { ParseResult, ParseOptions } from "./parse.js";
|
|
6
|
+
export { buildNavFromDirectory } from "./nav.js";
|
|
7
|
+
export type { BuildNavOptions } from "./nav.js";
|
|
8
|
+
export { loadNavFile } from "./nav-file.js";
|
|
9
|
+
export type { NavFile, NavFileItem, LoadNavFileOptions } from "./nav-file.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Dogsbay Markdown dialect — canonical format for TreeNode[].
|
|
2
|
+
//
|
|
3
|
+
// Spec: research/formats/dogsbay-markdown-spec.md
|
|
4
|
+
// Plan: plans/format-dogsbay-md.md
|
|
5
|
+
export { treeToDogsbayMd, nodeToDogsbayMd } from "./serialize.js";
|
|
6
|
+
export { inlineToDogsbayMd } from "./inline.js";
|
|
7
|
+
export { dogsbayMdToTree, parseInline } from "./parse.js";
|
|
8
|
+
export { buildNavFromDirectory } from "./nav.js";
|
|
9
|
+
export { loadNavFile } from "./nav-file.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kDAAkD;AAClD,mCAAmC;AAEnC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGlE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/inline.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline serialization — InlineNode[] → markdown text with inline formatting.
|
|
3
|
+
*/
|
|
4
|
+
import type { InlineNode } from "@dogsbay/types";
|
|
5
|
+
/**
|
|
6
|
+
* Serialize a flat array of inline nodes to markdown.
|
|
7
|
+
*/
|
|
8
|
+
export declare function inlineToDogsbayMd(nodes: InlineNode[] | undefined): string;
|
|
9
|
+
//# sourceMappingURL=inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../src/inline.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,gBAAgB,CAAC;AAG3D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,SAAS,GAAG,MAAM,CAGzE"}
|